//---------------------------
// Includes
//---------------------------
#include "Level.h"
#include "LevelElement.h"
#include "InputState.h"
#include "RenderContext.h"
#include "PhysX.h"
#include "GraphCamera.h"
#include <algorithm>
#include <boost/foreach.hpp>
//---------------------------
// Constructor & Destructor
//---------------------------
Level::Level(ID3D10Device *pD3DDevice, PhysX* physx)
:m_pD3DDevice(pD3DDevice)
	,m_pPhysX(physx)
	,m_GraphCamera(0)
{
	// nothing to create
}

Level::~Level()
{
	//delete all GraphElements
	for(unsigned int i=0;i<m_Nodes.size();++i)
	{
		SafeDelete (m_Nodes.at(i));
	}
}

void Level::AddChild(LevelElement *pNewGraphElement)
{
	pNewGraphElement->SetParent(this);
	m_Nodes.push_back(pNewGraphElement);
}

void Level::RemoveChild(LevelElement *childElement){
	vector<LevelElement*>::const_iterator foundElement;
	
	foundElement = std::find(m_Nodes.begin(),m_Nodes.end(),childElement);
	if ( foundElement != m_Nodes.end())
		m_Nodes.erase(foundElement);
}

void Level::Initialize(ContentManager *pContentManager, GraphCamera* graphcamera)
{
	m_GraphCamera = graphcamera;
	//call Initialize on every child
	std::vector<LevelElement*>::iterator  it;
	for(it=m_Nodes.begin();it<m_Nodes.end();++it)
	{
		(*it)->Initialize(pContentManager);
	}
}

void Level::Tick(const InputState & refInputState)
{
	//call Tick on every child
	std::vector<LevelElement*>::iterator  it;
	for(it=m_Nodes.begin();it<m_Nodes.end();++it)
	{
		D3DXVECTOR3 pos((*it)->GetWorldMatrix()._41, (*it)->GetWorldMatrix()._42, (*it)->GetWorldMatrix()._43);

		(*it)->EnableDraw(m_GraphCamera->CheckIfInFrustum(pos, (*it)->GetBoundingRadius()));
		(*it)->Tick(refInputState);
	}
}
	//
	//http://r3dux.org/2011/02/how-to-perform-manual-frustum-culling/
	//http://www.racer.nl/reference/vfc_markmorley.htm
void Level::Draw(const RenderContext* pRenderContext, ID3D10ShaderResourceView* shadowdepthmap)
{
	//performance kan hier beter TODO

	std::vector<LevelElement*>::const_iterator  it;
	//draw all non particle emitters
	for(it=m_Nodes.begin();it<m_Nodes.end();++it)
	{	
		if((*it)->GetName() != L"ParticleSystem")
			(*it)->Draw(pRenderContext, shadowdepthmap);
	}

	//now draw all particle emitters
	for(it=m_Nodes.begin();it<m_Nodes.end();++it)
	{
		//draw all non particle emitters
		if((*it)->GetName() == L"ParticleSystem")
			(*it)->Draw(pRenderContext, shadowdepthmap);
	}
}
void Level::DrawShadowMap(GraphCamera* pOrtohCam, D3DXMATRIX &mLightVolume
		,ID3D10Effect* BuildShadowMapFX)
{
	//call Draw on every child
	std::vector<LevelElement*>::const_iterator  it;
	for(it=m_Nodes.begin();it<m_Nodes.end();++it)
	{
		if((*it)->GetIfCastShadow())
		{
			(*it)->DrawToShadowmap(pOrtohCam, mLightVolume, BuildShadowMapFX);
		}
	}
}
void Level::OnResize(int clientWidth, int clientHeight)
{
	//call Draw on every child
	std::vector<LevelElement*>::const_iterator  it;
	for(it=m_Nodes.begin();it<m_Nodes.end();++it)
	{
		(*it)->OnResize(clientWidth, clientHeight);
	}
}
NxScene *Level::GetPhysicsScene() const 
{
	return m_pPhysX->GetScene();
}